package com.hutra.bitmap {
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.IBitmapDrawable;
	import flash.display.MovieClip;
	import flash.display.PixelSnapping;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * Data Mix
	 * 'Mi' as micro
	 * 'x' as factors that influence has been incalculable.
	 * 'Mix' as mix together different elements!
	 *
	 * @source  http://blog.hutrasoft.com/2011/11/movieclip-to-animal-bitmap.html
	 * @svn 	http://hutra.googlecode.com/svn/trunk/
	 * @wiki 	http://wiki.hutrasoft.com/2011/11/datamix.html
	 * @create 	11/05/2011 11:00:02 AM
	 * @author 	hungconcon
	 * @version 1.0.2
	 */
	public class DataMix {
		protected var _w:Number = -1;
		protected var _h:Number = -1;
		protected var _d:Array = null;
		
		/**
		 *
		 * @param	a Only Movieclip
		 * @param	b Only width, hight, not-including data
		 */
		public function DataMix(a:MovieClip, b:Boolean = true) {
			setup(a, b);
		}
		
		public function get width():Number {
			return this._w;
		}
		
		public function get height():Number {
			return this._h;
		}
		
		public function get data():Array {
			return this._d;
		}
		
		/**
		 * @param	a Make sure you seted the movie correctly!
		 * [1] Processing the movieclip, areas
		 * [2] Throw it!
		 */
		private function setup(a:MovieClip, f:Boolean):void {
			//[1]
			var b:Rectangle = getRecBase(a);
			//[1.1]
			if ((b.width <= 1) || (b.height <= 1)) {
				_d = new Array();
				_d.push(new BitmapData(1, 1, true, 0x00000000));
				_w = 1;
				_h = 1;
				return;
			}
			//[1.2]
			var c:Array = getListBase(a, b);
			var e:Rectangle = getRecActual(c, b);
			var k:Array = getListActual(c, e);
			var m:Rectangle = faceBitmap(k);
			//[2]
			_w = m.width;
			_h = m.height;
			if (f) {
				clear(c); // necessary!
				_d = getListActual(k, m);
			} else {
				clear(c); // necessary!
				clear(k); // necessary!
				_d = null;
			}
		}
		
		/**
		 * Remove excess parts not needed for bitmap
		 * @param	a
		 * @return Rectangle
		 */
		private function faceBitmap(a:Array):Rectangle {
			var c:Number = NaN;
			var d:Number = NaN;
			var e:Number = NaN;
			var f:Number = NaN;
			var g:Number = NaN;
			var h:Number = NaN;
			var k:Number = NaN;
			for (var i:int = 0; i < a.length; i++) {
				var b:Rectangle = a[i].getColorBoundsRect(0xFFFFFFFF, 0x000000, false);
				if (b.width != 0 && b.height != 0) { //b.x !=0 && b.y!=0 && 
					e = ((k = b.x) < e) ? k : (isNaN(e)) ? k : e;
					f = ((k = b.y) < f) ? k : (isNaN(f)) ? k : f;
					g = ((k = b.width) > g) ? k : (isNaN(g)) ? k : g;
					h = ((k = b.height) > h) ? k : (isNaN(h)) ? k : h;
					
					c = ((k = b.x + b.width) > c) ? k : (isNaN(c)) ? k : c;
					d = ((k = b.y + b.height) > d) ? k : (isNaN(d)) ? k : d;
				} else {
					// I dont like kind of asset!
				}
			}
			var m:Number = c - e;
			var n:Number = d - f;
			return new Rectangle(e, f, m, n);
		}
		
		/**
		 * Determine the total area and the initial coordinates of the object.
		 * [1]
		 * Find the smallest value x
		 * Find the smallest value of y
		 * Find the largest value of x
		 * Find the largest value of y
		 * [2]
		 * Find the largest value of width
		 * Find the largest value of hight
		 * [3]
		 * draw an object allows you to define regions of the object
		 * we will remove it when we get the full picture
		 * [4]
		 * Specify the width and height from [1],[2]
		 * @param	a
		 * @return Rectangle
		 */
		private function getRecBase(a:MovieClip):Rectangle {
			var c:int = a.totalFrames;
			var d:Number = NaN;
			var f:Number = NaN;
			var g:Number = NaN;
			var k:Number = NaN;
			var n:Number = NaN;
			var m:Number = NaN;
			var o:Number = NaN;
			//[1]
			for (var i:int = 1; i <= c; i++) {
				a.gotoAndStop(i);
				var b:Rectangle = a.getBounds(a);
				
				g = ((o = b.x) < g) ? o : (isNaN(g)) ? o : g;
				k = ((o = b.y) < k) ? o : (isNaN(k)) ? o : k;
				n = ((o = b.width) > n) ? o : (isNaN(n)) ? o : n;
				m = ((o = b.height) > m) ? o : (isNaN(m)) ? o : m;
				
				d = ((o = b.x + b.width) > d) ? o : (isNaN(d)) ? o : d;
				f = ((o = b.y + b.height) > f) ? o : (isNaN(f)) ? o : f;
			}
			//[2]
			var p:Number = d - g;
			var q:Number = f - k;
			//[3]
			var t:Sprite = new Sprite();
			t.name = "data_sprite";
			t.graphics.beginFill(0x000, 0);
			t.graphics.drawRect(g, k, p, q);
			t.graphics.endFill();
			t.mouseEnabled = false;
			t.mouseChildren = false;
			
			if (a.getChildByName("data_sprite")) {
				trace("alreadly add to stage!");
			} else {
				a.addChild(t);
			}
			//[4]	
			var z:Number = dePercent(a.scaleX * 100, 0, p);
			var y:Number = dePercent(a.scaleX * 100, 0, q);
			
			return new Rectangle(g, k, z, y);
		}
		
		/**
		 * Retrieving images based on the basic rectangle
		 * @param	a
		 * @param	b
		 * @return
		 */
		private function getListBase(a:MovieClip, b:Rectangle):Array {
			var d:int = a.totalFrames;
			var c:Array = new Array();
			for (var i:int = 1; i <= d; i++) {
				a.gotoAndStop(i);
				c.push(getBaseBitmapData(a, b, true));
			}
			return c;
		}
		
		/**
		 * Find a new Rectangle not including the superfluous
		 * @param	a
		 * @param	b
		 * @return
		 */
		private function getRecActual(a:Array, b:Rectangle):Rectangle {
			var d:Number = NaN;
			var e:Number = NaN;
			var f:Number = NaN;
			var g:BitmapData;
			var h:Rectangle;
			for (var i:int = 0; i < a.length; i++) {
				g = a[i] as BitmapData;
				h = getViboty(g, b);
				d = ((f = h.x) < d) ? f : (isNaN(d)) ? f : d;
				e = ((f = h.y) < e) ? f : (isNaN(e)) ? f : e;
			}
			return new Rectangle(d, e, b.width - d, b.height - e);
		}
		
		/**
		 * Get visible bounds of transparent
		 * [1] Frees memory that is used to store the BitmapData object.
		 * @param	a
		 * @param	b
		 * @return Rectangle
		 */
		private function getViboty(a:BitmapData, b:Rectangle):Rectangle {
			var c:BitmapData = new BitmapData(b.width, b.height, true, 0x00000000);
			c.draw(a);
			var d:Rectangle = c.getColorBoundsRect(0xFFFFFFFF, 0x000000, false);
			c.dispose(); //[1]
			return d;
		}
		
		/**
		 * [1] Frees memory that is used to store the BitmapData object.
		 * @param	a
		 * @param	b
		 * @return Array
		 */
		private function getListActual(a:Array, b:Rectangle):Array {
			var c:BitmapData;
			var d:Array = new Array();
			for (var i:int = 0; i < a.length; i++) {
				c = a[i] as BitmapData;
				d.push(getActutalBitmapData(c, b));
			}
			clear(a); //[1]
			return d;
		}
		
		/**
		 * Frees memory!
		 * @param	the arraylist
		 */
		public function clear(a:Array):void {
			if (a == null)
				return;
			for (var i:int = 0; i < a.length; i++)
				delete a.splice(i, 1);
			if (a != null)
				if (a.length > 0)
					clear(a);
			a = null;
		}
		
		/**
		 * Move
		 * Center point(0,0)
		 * |----------------|
		 * |	0.0			|
		 * |				|
		 * |		.---------------.
		 * |		|(80,80,100,90)	|
		 * |		|	Object		|
		 * |		|				|
		 * |		.---------------.
		 * |----------------|
		 *
		 * to
		 *
		 * .0.0------------.|
		 * |			   ||
		 * |	Object	   ||
		 * |			   ||
		 * .---------------.|
		 * |----------------|
		 *
		 * @param	a
		 * @param	b
		 * @return
		 */
		private function movePosition(a:Number, b:Number):Number {
			// -25 0 5 =  30 [1]
			// -25 0 -5 = 20 [2]
			//  5  0 25 = 20 [3]
			if (a > 0 && b > 0)
				return b - a; //[3]
			if (a < 0 && b < 0)
				return Math.abs(a) - Math.abs(b); //[2]
			if (a < 0 && b > 0)
				return Math.abs(a) + b; //[1]
			return 0;
		}
		
		/**
		 * [1],[2],[3] Scaled
		 * @param	a
		 * @param	b
		 * @param	c
		 * @return BitmapData
		 */
		private function getBaseBitmapData(a:MovieClip, b:Rectangle, c:Boolean):BitmapData {
			//[1]
			var f:Rectangle = a.getBounds(a);
			var g:Matrix = new Matrix(1, 0, 0, 1, -f.x, -f.y);
			g.scale(a.scaleX, a.scaleX);
			
			var wi:Number = dePercent(a.scaleX * 100, 0, f.width); //[2]
			var hi:Number = dePercent(a.scaleX * 100, 0, f.height); //[3]
			//[4]
			var h:BitmapData = new BitmapData(b.width, b.height, true, 0x00FFFFFF);
			h.draw(a, g, null, null, null, c);
			//[5]
			var xpo:Number = movePosition(b.x, f.x);
			var ypo:Number = movePosition(b.y, f.y);
			//[6]	
			var k:BitmapData = new BitmapData(b.width, b.height, true, 0x00FFFFFF);
			k.copyPixels(h, new Rectangle(0, 0, b.width, b.height), new Point(xpo, ypo));
			//[7]
			h.dispose();
			
			return k;
		}
		
		/**
		 * Function on lib: NumberUtilities.as.dePercent()
		 * Percentage change from the current number
		 * @see http://blog.hutrasoft.com/2011/10/16-useful-mathematical-formulas-in.html
		 * @param	percent
		 * @param	start
		 * @param	end
		 * @return number
		 */
		public static function dePercent(p:Number, s:Number = 0, e:Number = 100):Number {
			return (e - ((e - s) - ((p / 100) * (e - s))));
		}
		
		/**
		 * [2] Frees memory that is used to store the BitmapData object.
		 * @param	h
		 * @param	b
		 * @return BitmapData
		 */
		private function getActutalBitmapData(a:BitmapData, b:Rectangle):BitmapData {
			//[1]
			var k:BitmapData = new BitmapData(b.width, b.height, true, 0x00FFFFFF);
			k.copyPixels(a, new Rectangle(b.x, b.y, b.width, b.height), new Point(0, 0));
			//[2]
			a.dispose();
			
			return k;
		}
	
	}
}